package com.dy.base.dao.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.apache.commons.lang.StringUtils;

import com.dy.base.dao.JdbcDao;
import com.dy.base.dao.JdbcSzDao;
import com.dy.base.exception.ServiceException;
import com.dy.base.model.Page;
import com.dy.base.model.PageImpl;
import com.dy.base.model.Pageable;

public class BaseDaoImpl<T, PK extends Serializable> {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Value("${datasource.sz}")
	private String DB_SZ;
	private JdbcDao<T> jdbcDao;
	private JdbcSzDao<T> jdbcSzDao;
	private String exceptionMsg = "当前操作出现异常";

	public void setExceptionMsg(String exceptionMsg) {
		this.exceptionMsg = exceptionMsg;
	}
	public JdbcDao<T> getJdbcDao() {
		return jdbcDao;
	}

	@Autowired
	public void setJdbcDao(JdbcDao<T> jdbcDao) {
		this.jdbcDao = jdbcDao;
	}
	public JdbcSzDao<T> getJdbcSzDao() {
		return jdbcSzDao;
	}
	
	@Autowired
	public void setJdbcSzDao(JdbcSzDao<T> jdbcSzDao) {
		this.jdbcSzDao = jdbcSzDao;
	}
	
	@SuppressWarnings({ "rawtypes" })
	public List<T> list(String sql, ParameterizedRowMapper rowMapper,
			final Object... values) throws ServiceException {
		return list(sql, rowMapper, null, values);

	}
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<T> list(String sql, ParameterizedRowMapper rowMapper,String dataSource,
			final Object... values) throws ServiceException {
		try {
			if(DB_SZ.equals(dataSource)){
				return this.getJdbcSzDao().getJdbcTemplate().query(sql, rowMapper,
						values);
			}
			return this.getJdbcDao().getJdbcTemplate().query(sql, rowMapper,
					values);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(exceptionMsg, e.getCause());
			throw new ServiceException(exceptionMsg);
		}

	}
	
	@SuppressWarnings({ "rawtypes" })
	public T find(String sql, ParameterizedRowMapper rowMapper,
			final Object... values) throws ServiceException {
		return find( sql,rowMapper, null,values);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public T find(String sql, ParameterizedRowMapper rowMapper,String dataSource,
			final Object... values) throws ServiceException {
		try {
			List<T> list = null;
			if(DB_SZ.equals(dataSource)){
				list = this.getJdbcSzDao().getJdbcTemplate().query(sql,rowMapper, values);
			}else{
				list = this.getJdbcDao().getJdbcTemplate().query(sql,rowMapper, values);
			}
			if (list != null && list.size() != 0) {
				return list.get(0);
			}
			return null;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(exceptionMsg, e.getCause());
			throw new ServiceException(exceptionMsg);
		}
	}
	
	public boolean update(String sql, final Object... values){
		return update(sql, null,values);
	}
	
	public boolean update(String sql, String dataSource,final Object... values)
			throws ServiceException {
		try {
			int result=0;
			if(DB_SZ.equals(dataSource)){
				result = this.getJdbcSzDao().getJdbcTemplate().update(sql, values);
			}else{
				result = this.getJdbcDao().getJdbcTemplate().update(sql, values);
			}
			if (result < 1) {
				return false;
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(exceptionMsg, e.getCause());
			throw new ServiceException(exceptionMsg);
		}
	}
	
	public boolean batchUpdate(String sql,Object[] args){
		return batchUpdate(sql,null,args);
	}
	
	public boolean batchUpdate(String sql,String dataSource, Object[] args)
			throws ServiceException {
		try {
			List<Object[]> list = new ArrayList<>();
			for (Object obj : args) {
				Object[] o = new Object[] { obj };
				list.add(o);
			}
			int[] result = null;
			if(DB_SZ.equals(dataSource)){
				result = this.getJdbcSzDao().getJdbcTemplate().batchUpdate(sql,list);
			}else{
				result = this.getJdbcDao().getJdbcTemplate().batchUpdate(sql,list);
			}
			if (result!=null && result.length == args.length) {
				return true;
			}
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(exceptionMsg, e.getCause());
			throw new ServiceException(exceptionMsg);
		}
	}
	
	@SuppressWarnings("rawtypes")
	public Page<T> findPage(Pageable pageable, final String sql,final String countSql,ParameterizedRowMapper rowMapper,
			final Object... values) {
		return findPage(pageable,sql,countSql,null,rowMapper,values);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Page<T> findPage(Pageable pageable, final String sql,final String countSql,String dataSource,ParameterizedRowMapper rowMapper,
			final Object... values) {
		long totalCount = this.countSqlSize(countSql,dataSource, values);
		
		int startNo = (pageable.getPageNumber()-1)*pageable.getPageSize();
		int endNo = startNo + pageable.getPageSize();
		
		String sqlStr ="";
		if(startNo==0){
			sqlStr = "select * from("+sql+") where rownum <= " +  endNo;
		}
		if(startNo >0){
			sqlStr = "select * from(select row_.*, rownum rownum_ from("+sql+")" +
					"row_ where rownum <= " + endNo + ") where rownum_ > " + startNo;
		}
		Page<T> page = null;
		try {
			List<T> list = null;
			if(DB_SZ.equals(dataSource)){
				list = (List<T>) this.getJdbcSzDao().getJdbcTemplate().query(sqlStr, rowMapper,values);
			}else{
				list = (List<T>) this.getJdbcDao().getJdbcTemplate().query(sqlStr, rowMapper,values);
			}
			
			page = new PageImpl<T>(list, pageable, totalCount);
		} catch (DataAccessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return page;
	}
	
	@SuppressWarnings({ "rawtypes" })
	public Page<T> findPage(Pageable pageable, final String sql,ParameterizedRowMapper rowMapper ,final Object... values) {
		return findPage(pageable, sql,rowMapper,null, values);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Page<T> findPage(Pageable pageable, final String sql,ParameterizedRowMapper rowMapper,String dataSource,final Object... values) {
		long totalCount = this.countSqlResult(sql,dataSource, values);
		int startNo = (pageable.getPageNumber()-1)*pageable.getPageSize();
		int endNo = startNo + pageable.getPageSize();
		
		String sqlStr ="";
		if(startNo==0){
			sqlStr = "select * from("+sql+") where rownum <= " +  endNo;
		}
		if(startNo >0){
			sqlStr = "select * from(select row_.*, rownum rownum_ from("+sql+")" +
					"row_ where rownum <= " + endNo + ") where rownum_ > " + startNo;
		}
		Page<T> page = null;
		try {
			List<T> list = null;
			if(DB_SZ.equals(dataSource)){
				list = (List<T>) this.getJdbcSzDao().getJdbcTemplate().query(sqlStr, rowMapper,values);
			}else{
				list = (List<T>) this.getJdbcDao().getJdbcTemplate().query(sqlStr, rowMapper,values);
			}
			page = new PageImpl<T>(list, pageable, totalCount);
		} catch (DataAccessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return page;
	}
	
	
	/**
	 * 执行count查询获得本次sql查询所能获得的对象总数.
	 * 本函数只能自动处理简单的sql语句,复杂的sql查询请另行编写count语句查询.
	 */
	protected long countSqlSize(final String countSql,String dataSource, final Object... values) {
		try {
			Long count = findUnique(countSql,dataSource,values);
			return count;
		} catch (Exception e) {
			throw new RuntimeException("sql can't be auto count, sql is:" + countSql, e);
		}
	}
	/**
	 * 执行count查询获得本次sql查询所能获得的对象总数.
	 * 
	 * 本函数只能自动处理简单的sql语句,复杂的sql查询请另行编写count语句查询.
	 */
	protected long countSqlResult(final String sql, String dataSource,final Object... values) {
		String fromSql = sql;
		//select子句与order by子句会影响count查询,进行简单的排除.
		fromSql = "from " + StringUtils.substringAfter(fromSql, "from");
		fromSql = StringUtils.substringBefore(fromSql, "order by");

		String countSql = "select count(*) " + fromSql;

		try {
			Long count = findUnique(countSql,dataSource, values);
			return count;
		} catch (Exception e) {
			throw new RuntimeException("sql can't be auto count, sql is:" + countSql, e);
		}
	}
	
	/**
	 * 按sQL查询唯一对象.
	 * 
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	public <X> long findUnique(final String sql,String dataSource, final Object... values) {
		if(DB_SZ.equals(dataSource)){
			return this.getJdbcSzDao().getJdbcTemplate().queryForObject(sql, values,Long.class);
		}else{
			return this.getJdbcDao().getJdbcTemplate().queryForObject(sql, values,Long.class);
		}
	}
}


